use graphics::cosmic_text::Color;
use graphics::piet::{Text, TextLayout as TL, TextLayoutBuilder};
use graphics::{BorderRadii, Box2D, Frame, Point, Size, TextLayout, Transform3D};

use crate::contexts::{EventCtx, LayoutCtx, LifeCycleCtx, PaintCtx};
use crate::event::{Event, LifeCycle};
use crate::id::IdPath;
use crate::message::Message;
use crate::widget::Widget;

const PADDING: f32 = 20.0;
const STROKE_WIDTH: f32 = 2.0;
pub struct Button {
    pub text: String,
    layout: Option<TextLayout>,
    id_path: IdPath,
}

impl Button {
    pub fn new(text: String, id_path: IdPath) -> Self {
        Self {
            text,
            layout: None,
            id_path,
        }
    }
}

impl Widget for Button {
    fn event(&mut self, cx: &mut EventCtx, event: &Event) {
        match event {
            Event::MousePressed(_) => {
                cx.set_active(true);
                cx.request_paint();
            }
            Event::MouseReleased(_) => {
                if cx.is_active() && cx.is_hot() {
                    let message = Message {
                        id_path: self.id_path.clone(),
                        body: Box::new(()),
                    };
                    cx.cx_state.messages.push_back(message);
                    cx.request_layout()
                }
                cx.set_active(false);
                cx.request_paint();
            }
            _ => {}
        }
    }

    fn paint(&mut self, cx: &mut PaintCtx, g: &mut Frame) {
        let Some(layout) = &self.layout else {
            return;
        };
        let rect = Box2D::from_origin_and_size(
            Point::origin(),
            Size::new(
                2.0 * PADDING + layout.size().width as f32,
                2.0 * PADDING + layout.size().height as f32,
            ),
        );
        if cx.is_active() {
            g.rounded_rect(&rect, &BorderRadii::new(5.0), [0.4, 0.4, 0.4, 1.0]);
        } else if cx.is_hot() {
            g.rounded_rect(&rect, &BorderRadii::new(5.0), [0.8, 0.8, 0.8, 1.0]);
        } else {
            g.rounded_rect(&rect, &BorderRadii::new(5.0), [1.0; 4]);
        }
        g.rounded_rect_stroke(
            &rect,
            &BorderRadii::new(5.0),
            [0.0, 0.0, 0.0, 1.0],
            STROKE_WIDTH,
        );
        g.draw_text(
            &layout,
            Color::rgb(0, 0, 0),
            Transform3D::translation(PADDING, PADDING, 0.0),
        );
    }

    fn layout(&mut self, cx: &mut LayoutCtx) -> Size {
        let layout_builder = cx.brush_cx.new_text_layout(self.text.to_string());
        let layout = layout_builder.build().unwrap();
        let size = layout.size();
        self.layout = Some(layout);
        Size::new(
            2.0 * PADDING + size.width as f32,
            2.0 * PADDING + size.height as f32,
        ) + Size::new(STROKE_WIDTH, STROKE_WIDTH)
    }

    fn lifecycle(&mut self, cx: &mut LifeCycleCtx, event: &LifeCycle) {
        if let LifeCycle::HotChanged(_) = event {
            cx.request_paint();
        }
    }
}
